using System;
using System.Drawing;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using PUPFILELib;

namespace PupViewer
{
	/// <summary>
	/// Summary description for PupViewer.
	/// </summary>
	public class PupViewer : System.Windows.Forms.Form
    {
        #region Private Variables

        #region Constants

        private const int STGM_SIMPLE = 0x08000000;
		private const int STGM_READ = 0x00000000;
		private const int STGM_SHARE_DENY_NONE = 0x00000020;
		private const int  STGM_SHARE_EXCLUSIVE = 0x00000010;
		private const string initialDirectory = @"c:\";
		private const string fileFilter = "pup files (*.pup)|*.pup";
        
        #endregion Constants

        private System.ComponentModel.IContainer components;
        private TreeNode currentNode = null;
		private CompoundFile g_objCompoundFile = null;
		private string fileName = null;
        private string cabfile = null;
		private System.Windows.Forms.MainMenu fileMnu;
		private System.Windows.Forms.MenuItem menuItem4;
		private System.Windows.Forms.MenuItem mnuAbout;
		private System.Windows.Forms.MenuItem mnuFile;
		private System.Windows.Forms.MenuItem mnuOpenFile;
		private System.Windows.Forms.MenuItem mnuReset;
		private System.Windows.Forms.TreeView pupView;
		private System.Windows.Forms.Splitter Pupsplitter;
		private System.Windows.Forms.ListView PupFilelist;
		private System.Windows.Forms.ImageList PupViewerimageList;
		private System.Windows.Forms.ContextMenu pupViewercontextMnu;
		private System.Windows.Forms.MenuItem extractmenuItem;
		private System.Windows.Forms.TextBox pupFileContent;
		private System.Windows.Forms.SaveFileDialog savePupFileDialog;
		private System.Windows.Forms.FolderBrowserDialog folderPupBrowserDialog;
		private System.Windows.Forms.OpenFileDialog openPupFileDialog;

        #endregion Private Variables

        #region olde32

        /// <summary>
		/// Structured File access.
		/// </summary>
		class ole32
		{
			[DllImport("ole32.dll")]
			public static extern int StgOpenStorage (
				[MarshalAs(UnmanagedType.LPWStr)] string wcsName,
				IntPtr stgPriority,
				int grfMode,
				IntPtr snbExclude,
				int reserved,
				out UCOMIStorage storage
				);
			
			[DllImport("ole32.dll")]
			public static extern int StgIsStorageFile(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsName
				);
		}

		/// <summary>
		/// 
		/// </summary>
		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000d-0000-0000-C000-000000000046")]
		interface IEnumSTATSTG 
		{
			[PreserveSig]
			int Next(uint celt, out STATSTG rgelt, out uint pceltFetched);
			[PreserveSig]
			int Skip(uint celt);
			[PreserveSig]
			int Reset();
			[PreserveSig]
			int Clone(out IEnumSTATSTG ppenum);
		}

		/// <summary>
		/// Interface to Structured File.
		/// </summary>
		[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000b-0000-0000-C000-000000000046")]
		interface UCOMIStorage
		{
			[PreserveSig]
			int CreateStream(
				[MarshalAs(UnmanagedType.LPWStr)] string wcsName,
				int grfMode, //Access mode for the new stream
				int reserved1, //Reserved; must be zero
				int reserved2, //Reserved; must be zero
				out UCOMIStream stream //Pointer to output variable
				);

			[PreserveSig]
			int OpenStream(
				[MarshalAs(UnmanagedType.LPWStr)] string wcsName,
				IntPtr reserved1, //Reserved; must be NULL
				int grfMode, //Access mode for the new stream
				int reserved2, //Reserved; must be zero
				out UCOMIStream stream //Pointer to output variable
				);

			[PreserveSig]
			int CreateStorage(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
				int grfMode,
				int reserved1,
				int reserved2,
				out UCOMIStorage ppstg);

			[PreserveSig]
			int OpenStorage(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
				UCOMIStorage pstgPriority,
				int grfMode,
				[MarshalAs(UnmanagedType.LPWStr)] string snbExclude,
				int reserved,
				out UCOMIStorage ppstg
				);

			[PreserveSig]
			int CopyTo(
				int ciidExclude,
				Guid rgiidExclude,
				[MarshalAs(UnmanagedType.LPWStr)] string snbExclude,
				UCOMIStorage pstgDest
				);
        
			[PreserveSig]
			int MoveElementTo(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
				UCOMIStorage pstgDest,
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName,
				int grfFlags
				);

			[PreserveSig]
 			int Commit(
				int grfCommitFlags
				);

			[PreserveSig]
 			int Revert();

			[PreserveSig]
			int EnumElements( 
				int reserved1,		//Reserved; must be zero
				IntPtr reserved2,	//Reserved; must be NULL
				int reserved3,		//Reserved; must be zero
				out IEnumSTATSTG ppenum
				);
        
			[PreserveSig]
			int DestroyElement(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsName
				);
        
			[PreserveSig]
			int RenameElement(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsOldName,
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName
				);
        
			[PreserveSig]
			int SetElementTimes(
				[MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
				DateTime pctime,
				DateTime patime,
				DateTime pmtime
				);
        
			[PreserveSig]
			int SetClass(
				Guid clsid
				);
        
			[PreserveSig]
			int SetStateBits(
				int grfStateBits,
				int grfMask
				);
        
			[PreserveSig]
			int Stat(
				out STATSTG pstatstg,
				int grfStatFlag
				);
        }

        #endregion olde32
        
        public PupViewer()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PupViewer));
            this.pupView = new System.Windows.Forms.TreeView();
            this.PupViewerimageList = new System.Windows.Forms.ImageList(this.components);
            this.pupViewercontextMnu = new System.Windows.Forms.ContextMenu();
            this.extractmenuItem = new System.Windows.Forms.MenuItem();
            this.fileMnu = new System.Windows.Forms.MainMenu(this.components);
            this.mnuFile = new System.Windows.Forms.MenuItem();
            this.mnuOpenFile = new System.Windows.Forms.MenuItem();
            this.mnuReset = new System.Windows.Forms.MenuItem();
            this.menuItem4 = new System.Windows.Forms.MenuItem();
            this.mnuAbout = new System.Windows.Forms.MenuItem();
            this.openPupFileDialog = new System.Windows.Forms.OpenFileDialog();
            this.Pupsplitter = new System.Windows.Forms.Splitter();
            this.PupFilelist = new System.Windows.Forms.ListView();
            this.pupFileContent = new System.Windows.Forms.TextBox();
            this.savePupFileDialog = new System.Windows.Forms.SaveFileDialog();
            this.folderPupBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
            this.SuspendLayout();
            // 
            // pupView
            // 
            this.pupView.Dock = System.Windows.Forms.DockStyle.Left;
            this.pupView.ImageIndex = 0;
            this.pupView.ImageList = this.PupViewerimageList;
            this.pupView.Location = new System.Drawing.Point(0, 0);
            this.pupView.Name = "pupView";
            this.pupView.SelectedImageIndex = 1;
            this.pupView.Size = new System.Drawing.Size(216, 409);
            this.pupView.TabIndex = 4;
            this.pupView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect);
            this.pupView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pupView_MouseDown);
            // 
            // PupViewerimageList
            // 
            this.PupViewerimageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("PupViewerimageList.ImageStream")));
            this.PupViewerimageList.TransparentColor = System.Drawing.Color.Transparent;
            this.PupViewerimageList.Images.SetKeyName(0, "");
            this.PupViewerimageList.Images.SetKeyName(1, "");
            this.PupViewerimageList.Images.SetKeyName(2, "");
            this.PupViewerimageList.Images.SetKeyName(3, "");
            this.PupViewerimageList.Images.SetKeyName(4, "");
            // 
            // pupViewercontextMnu
            // 
            this.pupViewercontextMnu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.extractmenuItem});
            // 
            // extractmenuItem
            // 
            this.extractmenuItem.Index = 0;
            this.extractmenuItem.Text = "Extract To...";
            this.extractmenuItem.Click += new System.EventHandler(this.extractmenuItem_Click);
            // 
            // fileMnu
            // 
            this.fileMnu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.mnuFile,
            this.menuItem4});
            // 
            // mnuFile
            // 
            this.mnuFile.Index = 0;
            this.mnuFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.mnuOpenFile,
            this.mnuReset});
            this.mnuFile.Text = "File";
            // 
            // mnuOpenFile
            // 
            this.mnuOpenFile.Index = 0;
            this.mnuOpenFile.Text = "Open File";
            this.mnuOpenFile.Click += new System.EventHandler(this.mnuOpenFile_Click);
            // 
            // mnuReset
            // 
            this.mnuReset.Index = 1;
            this.mnuReset.Text = "Reset Application";
            this.mnuReset.Click += new System.EventHandler(this.mnuReset_Click);
            // 
            // menuItem4
            // 
            this.menuItem4.Index = 1;
            this.menuItem4.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.mnuAbout});
            this.menuItem4.Text = "Help";
            // 
            // mnuAbout
            // 
            this.mnuAbout.Index = 0;
            this.mnuAbout.Text = "About";
            this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click);
            // 
            // openPupFileDialog
            // 
            this.openPupFileDialog.Title = "Open Pup File";
            // 
            // Pupsplitter
            // 
            this.Pupsplitter.Location = new System.Drawing.Point(216, 0);
            this.Pupsplitter.Name = "Pupsplitter";
            this.Pupsplitter.Size = new System.Drawing.Size(3, 409);
            this.Pupsplitter.TabIndex = 6;
            this.Pupsplitter.TabStop = false;
            // 
            // PupFilelist
            // 
            this.PupFilelist.Dock = System.Windows.Forms.DockStyle.Fill;
            this.PupFilelist.FullRowSelect = true;
            this.PupFilelist.Location = new System.Drawing.Point(219, 0);
            this.PupFilelist.Name = "PupFilelist";
            this.PupFilelist.Size = new System.Drawing.Size(461, 409);
            this.PupFilelist.TabIndex = 7;
            this.PupFilelist.UseCompatibleStateImageBehavior = false;
            this.PupFilelist.Visible = false;
            this.PupFilelist.MouseUp += new System.Windows.Forms.MouseEventHandler(this.PupFilelist_MouseUp);
            // 
            // pupFileContent
            // 
            this.pupFileContent.Dock = System.Windows.Forms.DockStyle.Fill;
            this.pupFileContent.Location = new System.Drawing.Point(219, 0);
            this.pupFileContent.Multiline = true;
            this.pupFileContent.Name = "pupFileContent";
            this.pupFileContent.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.pupFileContent.Size = new System.Drawing.Size(461, 409);
            this.pupFileContent.TabIndex = 8;
            this.pupFileContent.WordWrap = false;
            // 
            // PupViewer
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(680, 409);
            this.Controls.Add(this.pupFileContent);
            this.Controls.Add(this.PupFilelist);
            this.Controls.Add(this.Pupsplitter);
            this.Controls.Add(this.pupView);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Menu = this.fileMnu;
            this.Name = "PupViewer";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Pup Viewer 2007";
            this.ResumeLayout(false);
            this.PerformLayout();

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new PupViewer());
		}

		private void DisplayStorageTree(string pwszStorageName, UCOMIStorage storage, TreeNode tn)
		{
			IEnumSTATSTG ppenum;
			UCOMIStorage pStgChild = null;
			STATSTG statstg = new STATSTG();
			int hr = -1;

			try
			{
				// get the elements to enumerate
				hr = storage.EnumElements(0, IntPtr.Zero, 0, out ppenum);

				uint dummy = 0;
				uint i = 1;

				// loop through all elements
				while(0 == ppenum.Next(i, out statstg, out dummy))
				{
					// if type is one then we have a storage
					if(1==statstg.type && @"" !=statstg.pwcsName[0].ToString())
					{
						TreeNode tn2 = new TreeNode(statstg.pwcsName);
						tn.Nodes.Add(tn2);
						hr = storage.OpenStorage(statstg.pwcsName, null, STGM_READ | STGM_SHARE_EXCLUSIVE, null, 0,out pStgChild);

						DisplayStorageTree(statstg.pwcsName, pStgChild, tn2);
					}
					// if type is 2 then we have a stream
					if(2==statstg.type && @"" !=statstg.pwcsName[0].ToString())
					{
						TreeNode tn3 = tn.Nodes.Add(statstg.pwcsName);
						UCOMIStream stream = null;
						storage.OpenStream(statstg.pwcsName, IntPtr.Zero, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, out stream);
						tn3.Tag = "stream";
						switch(statstg.pwcsName)
						{
                            case "IISData":
							case "Config":
								tn3.ImageIndex = 2;
								tn3.SelectedImageIndex = 2;
								break;
							default:
								tn3.ImageIndex = 3;
								tn3.SelectedImageIndex = 3;
								break;
						}
					}
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private void treeView1_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
		{
            string pupfilename = null;

			// work with a clean enviroment
			PupFilelist.Items.Clear();
			pupFileContent.Text = "";
			currentNode = e.Node;

			try
			{
				if(((string)e.Node.Tag) == "stream")
				{
					g_objCompoundFile.Initialize(fileName, 0);
					switch(e.Node.Text)
					{
						case "Config":
                            SetTextProperties(pupfilename, e.Node, pupFileContent, PupFilelist);
							break;
						case "IISData":
                            SetTextProperties(pupfilename, e.Node, pupFileContent, PupFilelist);
							break;
						case "Data":
                            SetCabProperties(pupfilename, e.Node, pupFileContent, PupFilelist);
							break;
						case "Files":
                            SetCabProperties(pupfilename, e.Node, pupFileContent, PupFilelist);
							break;
					}
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
			
			if(pupfilename!=null)
			{
				// delete the file
				File.Delete(pupfilename);
			}
		}

        private void SetTextProperties(string pupfilename, TreeNode node, TextBox pupFileContent, ListView PupFilelist)
        {
            pupfilename = @"c:\" + node.Text + ".txt";
            pupFileContent.Visible = true;
            PupFilelist.Visible = false;
            CopyToFileFromStream(pupfilename, g_objCompoundFile, node.Parent.Text, node.Text);
            DispalyTextFile(pupfilename);
        }

        private void SetCabProperties(string pupfilename, TreeNode node, TextBox pupFileContent, ListView PupFilelist)
        {
            pupfilename = @"c:\" + node.Text + ".cab";
            pupFileContent.Visible = false;
            PupFilelist.Visible = true;
            CopyToFileFromStream(pupfilename, g_objCompoundFile, node.Parent.Text, node.Text);
            DisplayCabFiles(pupfilename);
        }

        private void CopyToFileFromStream(string filename, CompoundFile g_objCompoundFile, string parentnode, string currentnode)
		{
			// get the file then delete it when we are done with it
			g_objCompoundFile.CopyToFileFromStream(filename, parentnode, currentnode);
		}

		private void DispalyTextFile(string filename)
		{
			StreamReader str = File.OpenText(filename);
			pupFileContent.Text = str.ReadToEnd();
			str.Close();
		}

        private string GetCabarcPath()
        {
            return Environment.GetEnvironmentVariable("COMMERCE_SERVER_ROOT") + "Cabarc.exe";
        }

		private void DisplayCabFiles(string filename)
		{
			// set the process info
			ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = GetCabarcPath();
			startInfo.Arguments = "l "+filename;
			startInfo.UseShellExecute = false;
			startInfo.RedirectStandardOutput = true;
			startInfo.WindowStyle = ProcessWindowStyle.Hidden;

			// execute the process
			Process process = Process.Start(startInfo);
			string output = process.StandardOutput.ReadToEnd();
			process.WaitForExit();

			// now format the results
			// for now just add it to the listview
			
			char[] chr = new char[2];
			chr[0] = '\r';
			chr[1] = '\n';

			// parse out header data
			output = output.Substring(output.IndexOf("File name"), output.Length-output.IndexOf("File name"));

			string[] slines = new string[output.Split(chr).Length];
			string line = null;
			string[] listColumn = new string[5];
			string tempcol = null;
			
			slines = output.Split(chr);

			// set list to detail view
			PupFilelist.View = View.Details;
			PupFilelist.Columns.Clear();
			// set the columns for the list view
			PupFilelist.Columns.Add("File Name", 200, HorizontalAlignment.Left);
			PupFilelist.Columns.Add("File Size", 60, HorizontalAlignment.Left);
			PupFilelist.Columns.Add("Date", 70, HorizontalAlignment.Left);
			PupFilelist.Columns.Add("Time", 60, HorizontalAlignment.Left);
			PupFilelist.Columns.Add("Attributes", 50, HorizontalAlignment.Left);

			foreach(string s in slines)
			{
				if(s!="" && !s.StartsWith("-") && !s.StartsWith("File name"))
				{
					// take out the first space
					line = s.Trim(); //s.Substring(3, s.Length - 3);
					// now try taking out more spaces
					// should really do this with a regular expresion but I am lazy
					line = line.Replace("  ", " ").Replace("  ", " ").Replace("  ", " ");

					// loop five times and get the columns
					for(int j=4; j>=0; j--)
					{
						if(j!=0)
						{
							// work backwards to get the spaces split into the string array
							tempcol = line.Substring(line.LastIndexOf(" "));
							// now that we got our value remove it from the line
							line = line.Remove(line.LastIndexOf(" "), tempcol.Length);
							listColumn[j] = tempcol.Trim();
						}
						else
						{
							// since we are at the last record don't worry about spaces
							listColumn[j] = line.Trim();
						}
					}
					ListViewItem litem = new ListViewItem(listColumn);
					PupFilelist.Items.Add(litem);
				}
			}
		}

		private void mnuAbout_Click(object sender, System.EventArgs e)
		{
			About about = new About();
			about.ShowDialog(this);
		}

		private void mnuOpenFile_Click(object sender, System.EventArgs e)
		{
			g_objCompoundFile = new CompoundFileClass();
			openPupFileDialog.InitialDirectory = initialDirectory;
			openPupFileDialog.Filter = fileFilter;
			
			if(openPupFileDialog.ShowDialog() == DialogResult.OK)
			{
				if(openPupFileDialog.FileName!= null)
				{
					// clear the tree and the list
					pupView.Nodes.Clear();
					PupFilelist.Items.Clear();
					pupFileContent.Text = "";

					// get the file to work with
					fileName = openPupFileDialog.FileName;
					Int64 hr = 0;

					// set the root node
					TreeNode tn = pupView.Nodes.Add(fileName);
					tn.ImageIndex = 4;
					tn.SelectedImageIndex = 4;

					// is the file a compound file?
					hr = ole32.StgIsStorageFile(fileName);

					if(0==hr)
					{
						UCOMIStorage storage = null;
						int grfMode = STGM_READ | STGM_SHARE_DENY_NONE;
						int hResult = ole32.StgOpenStorage(fileName, IntPtr.Zero, grfMode, IntPtr.Zero, 0, out storage);

						DisplayStorageTree(fileName, storage, tn);
					}
					else
					{
						MessageBox.Show("Not a pup file");
					}
				}
			}

		}

		private void mnuReset_Click(object sender, System.EventArgs e)
		{
			pupView.Nodes.Clear();
			PupFilelist.Items.Clear();
			pupFileContent.Text = "";
			g_objCompoundFile = new CompoundFileClass();
		}

		private void extractmenuItem_Click(object sender, System.EventArgs e)
		{
			string pupfilename = null;
			folderPupBrowserDialog.Description = "Extract "+currentNode+" to ...";
            ProcessStartInfo startinfo = new ProcessStartInfo(GetCabarcPath());
			Process process;
			string cmdarg = null;
			folderPupBrowserDialog.ShowNewFolderButton = true;
			
			if(folderPupBrowserDialog.ShowDialog() == DialogResult.OK)
			{
				// extract the file
				g_objCompoundFile.Initialize(fileName, 0);
				
				switch(currentNode.Text)
				{
                    case "IISData":
					case "Config":
						pupfilename = @"c:\"+currentNode.Text+".txt";
						CopyToFileFromStream(pupfilename, g_objCompoundFile, currentNode.Parent.Text, currentNode.Text);
						File.Copy(pupfilename, folderPupBrowserDialog.SelectedPath+"\\"+currentNode.Text+".txt");
						break;
                    case "Files":
					case "Data":
						pupfilename = @"c:\"+currentNode.Text+".cab";
						CopyToFileFromStream(pupfilename, g_objCompoundFile, currentNode.Parent.Text, currentNode.Text);
						cmdarg = "-p -r -o X \""+pupfilename+"\" \""+folderPupBrowserDialog.SelectedPath+"\\";

						startinfo.Arguments = cmdarg;
						startinfo.UseShellExecute = false;
						startinfo.RedirectStandardOutput = true;
						process = Process.Start(startinfo);
						Trace.WriteLine(process.StandardOutput.ReadToEnd());
						process.WaitForExit();
						break;
				}
				File.Delete(pupfilename);
			}
		}

		private void pupView_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			try
			{
				// set the node we are working with
				if(e.Button == MouseButtons.Right)
				{
					currentNode = pupView.GetNodeAt(e.X, e.Y);
					currentNode.TreeView.SelectedNode = currentNode;
					if(currentNode.Tag!=null)
					{
						Point point = new Point(e.X, e.Y);
						pupViewercontextMnu.Show(pupView, point);
					}
				}
			}
			catch{}
		}

		private void ExtractFile(object sender, System.EventArgs e)
		{
			// only exxtract one file
			string pupfilename = null;
			folderPupBrowserDialog.Description = "Extract "+currentNode+" to ...";
            ProcessStartInfo startinfo = new ProcessStartInfo(GetCabarcPath());
			Process process;
			string cmdarg = null;
			folderPupBrowserDialog.ShowNewFolderButton = true;
			
			// display the folder
			if(folderPupBrowserDialog.ShowDialog() == DialogResult.OK)
			{
				// the file name to extract
				pupfilename = @"c:\"+currentNode.Text+".cab";
				CopyToFileFromStream(pupfilename, g_objCompoundFile, currentNode.Parent.Text, currentNode.Text);
				// now extract the file the user selected
				int lstidx = cabfile.LastIndexOf(@"\");
				cabfile = cabfile.Substring(lstidx+1).Trim();
				cmdarg = "-o X \""+pupfilename+"\" \""+cabfile+"\" \""+folderPupBrowserDialog.SelectedPath+"\\";

				startinfo.Arguments = cmdarg;
				startinfo.UseShellExecute = false;
				startinfo.RedirectStandardOutput = true;
				process = Process.Start(startinfo);
				Trace.WriteLine(process.StandardOutput.ReadToEnd());
				process.WaitForExit();

				File.Delete(pupfilename);
			}
		}

		private void PupFilelist_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			try
			{
				if(e.Button == MouseButtons.Right)
				{
					Point p = new Point(e.X, e.Y);
					ListViewItem litem = PupFilelist.SelectedItems[0] as ListViewItem;
					cabfile = litem.Text;
					pupViewercontextMnu.MenuItems.Clear();
					MenuItem extractFile = new MenuItem("Extract File...", new EventHandler(this.ExtractFile));
					pupViewercontextMnu.MenuItems.Add(extractFile);
					pupViewercontextMnu.Show(PupFilelist, p);
				}
			}
			catch{}
		}
	}
}
